home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / lib-src / movemail.c < prev    next >
C/C++ Source or Header  |  1993-11-16  |  16KB  |  766 lines

  1. /* movemail foo bar -- move file foo to file bar,
  2.    locking file foo the way /bin/mail respects.
  3.    Copyright (C) 1986, 1992 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* Important notice: defining MAIL_USE_FLOCK *will cause loss of mail*
  22.    if you do it on a system that does not normally use flock as its way of
  23.    interlocking access to inbox files.  The setting of MAIL_USE_FLOCK
  24.    *must agree* with the system's own conventions.
  25.    It is not a choice that is up to you.
  26.  
  27.    So, if your system uses lock files rather than flock, then the only way
  28.    you can get proper operation is to enable movemail to write lockfiles there.
  29.    This means you must either give that directory access modes
  30.    that permit everyone to write lockfiles in it, or you must make movemail
  31.    a setuid or setgid program.  */
  32.  
  33. /*
  34.  * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
  35.  *
  36.  * Added POP (Post Office Protocol) service.  When compiled -DPOP
  37.  * movemail will accept input filename arguments of the form
  38.  * "po:username".  This will cause movemail to open a connection to
  39.  * a pop server running on $MAILHOST (environment variable).  Movemail
  40.  * must be setuid to root in order to work with POP.
  41.  * 
  42.  * New module: popmail.c
  43.  * Modified routines:
  44.  *    main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
  45.  *        after POP code. 
  46.  * New routines in movemail.c:
  47.  *    get_errmsg - return pointer to system error message
  48.  *
  49.  */
  50.  
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include <sys/file.h>
  54. #include <errno.h>
  55. #define NO_SHORTNAMES   /* Tell config not to load remap.h */
  56. #include "../src/config.h"
  57.  
  58. #ifdef USG
  59. #include <fcntl.h>
  60. #include <unistd.h>
  61. #ifndef F_OK
  62. #define F_OK 0
  63. #define X_OK 1
  64. #define W_OK 2
  65. #define R_OK 4
  66. #endif
  67. #endif /* USG */
  68.  
  69. #ifdef XENIX
  70. #include <sys/locking.h>
  71. #endif
  72.  
  73. #ifdef MAIL_USE_MMDF
  74. extern int lk_open (), lk_close ();
  75. #endif
  76.  
  77. /* Cancel substitutions made by config.h for Emacs.  */
  78. #undef open
  79. #undef read
  80. #undef write
  81. #undef close
  82.  
  83. char *malloc ();
  84. char *strcpy ();
  85. char *concat ();
  86. char *xmalloc ();
  87. #ifndef errno
  88. extern int errno;
  89. #endif
  90.  
  91. /* Nonzero means this is name of a lock file to delete on fatal error.  */
  92. char *delete_lockname;
  93.  
  94. main (argc, argv)
  95.      int argc;
  96.      char **argv;
  97. {
  98.   char *inname, *outname;
  99.   int indesc, outdesc;
  100.   int nread;
  101.  
  102. #ifndef MAIL_USE_FLOCK
  103.   struct stat st;
  104.   long now;
  105.   int tem;
  106.   char *lockname, *p;
  107.   char *tempname;
  108.   int desc;
  109. #endif /* not MAIL_USE_FLOCK */
  110.  
  111.   delete_lockname = 0;
  112.  
  113.   if (argc < 3)
  114.     fatal ("two arguments required");
  115.  
  116.   inname = argv[1];
  117.   outname = argv[2];
  118.  
  119. #ifdef MAIL_USE_MMDF
  120.   mmdf_init (argv[0]);
  121. #endif
  122.  
  123.   /* Check access to output file.  */
  124.   if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
  125.     pfatal_with_name (outname);
  126.  
  127.   /* Also check that outname's directory is writeable to the real uid.  */
  128.   {
  129.     char *buf = (char *) malloc (strlen (outname) + 1);
  130.     char *p, q;
  131.     strcpy (buf, outname);
  132.     p = buf + strlen (buf);
  133.     while (p > buf && p[-1] != '/')
  134.       *--p = 0;
  135.     if (p == buf)
  136.       *p++ = '.';
  137.     if (access (buf, W_OK) != 0)
  138.       pfatal_with_name (buf);
  139.     free (buf);
  140.   }
  141.  
  142. #ifdef MAIL_USE_POP
  143.   if (!strncmp (inname, "po:", 3))
  144.     {
  145.       int status; char *user;
  146.  
  147.       for (user = &inname[strlen (inname) - 1]; user >= inname; user--)
  148.     if (*user == ':')
  149.       break;
  150.  
  151.       status = popmail (user, outname);
  152.       exit (status);
  153.     }
  154.  
  155.   setuid (getuid ());
  156. #endif /* MAIL_USE_POP */
  157.  
  158.   /* Check access to input file.  */
  159.   if (access (inname, R_OK | W_OK) != 0)
  160.     pfatal_with_name (inname);
  161.  
  162. #ifndef MAIL_USE_MMDF
  163. #ifndef MAIL_USE_FLOCK
  164.   /* Use a lock file named /usr/spool/mail/$USER.lock:
  165.      If it exists, the mail file is locked.  */
  166.   /* Note: this locking mechanism is *required* by the mailer
  167.      (on systems which use it) to prevent loss of mail.
  168.  
  169.      On systems that use a lock file, extracting the mail without locking
  170.      WILL occasionally cause loss of mail due to timing errors!
  171.  
  172.      So, if creation of the lock file fails
  173.      due to access permission on /usr/spool/mail,
  174.      you simply MUST change the permission
  175.      and/or make movemail a setgid program
  176.      so it can create lock files properly.
  177.  
  178.      You might also wish to verify that your system is one
  179.      which uses lock files for this purpose.  Some systems use other methods.
  180.  
  181.      If your system uses the `flock' system call for mail locking,
  182.      define MAIL_USE_FLOCK in config.h or the s-*.h file
  183.      and recompile movemail.  If the s- file for your system
  184.      should define MAIL_USE_FLOCK but does not, send a bug report
  185.      to bug-gnu-emacs@prep.ai.mit.edu so we can fix it.  */
  186.  
  187.   lockname = concat (inname, ".lock", "");
  188.   tempname = strcpy (xmalloc (strlen (inname)+1), inname);
  189.   p = tempname + strlen (tempname);
  190.   while (p != tempname && p[-1] != '/')
  191.     p--;
  192.   *p = 0;
  193.   strcpy (p, "EXXXXXX");
  194.   mktemp (tempname);
  195.   unlink (tempname);
  196.  
  197.   while (1)
  198.     {
  199.       /* Create the lock file, but not under the lock file name.  */
  200.       /* Give up if cannot do that.  */
  201.       desc = open (tempname, O_WRONLY | O_CREAT, 0666);
  202.       if (desc < 0)
  203.         pfatal_with_name ("lock file--see source file etc/movemail.c");
  204.       close (desc);
  205.  
  206.       tem = link (tempname, lockname);
  207.       unlink (tempname);
  208.       if (tem >= 0)
  209.     break;
  210.       sleep (1);
  211.  
  212.       /* If lock file is a minute old, unlock it.  */
  213.       if (stat (lockname, &st) >= 0)
  214.     {
  215.       now = time (0);
  216.       if (st.st_ctime < now - 60)
  217.         unlink (lockname);
  218.     }
  219.     }
  220.  
  221.   delete_lockname = lockname;
  222. #endif /* not MAIL_USE_FLOCK */
  223.  
  224. #ifdef MAIL_USE_FLOCK
  225.   indesc = open (inname, O_RDWR);
  226. #else /* if not MAIL_USE_FLOCK */
  227.   indesc = open (inname, O_RDONLY);
  228. #endif /* not MAIL_USE_FLOCK */
  229. #else /* MAIL_USE_MMDF */
  230.   indesc = lk_open (inname, O_RDONLY, 0, 0, 10);
  231. #endif /* MAIL_USE_MMDF */
  232.  
  233.   if (indesc < 0)
  234.     pfatal_with_name (inname);
  235.  
  236. #if defined (BSD) || defined (XENIX)
  237.   /* In case movemail is setuid to root, make sure the user can
  238.      read the output file.  */
  239.   /* This is desirable for all systems
  240.      but I don't want to assume all have the umask system call */
  241.   umask (umask (0) & 0333);
  242. #endif /* BSD or Xenix */
  243.   outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
  244.   if (outdesc < 0)
  245.     pfatal_with_name (outname);
  246. #ifdef MAIL_USE_FLOCK
  247. #ifdef XENIX
  248.   if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);
  249. #else
  250.   if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname);
  251. #endif
  252. #endif /* MAIL_USE_FLOCK */
  253.  
  254.   {
  255.     char buf[1024];
  256.  
  257.     while (1)
  258.       {
  259.     nread = read (indesc, buf, sizeof buf);
  260.     if (nread != write (outdesc, buf, nread))
  261.       {
  262.         int saved_errno = errno;
  263.         unlink (outname);
  264.         errno = saved_errno;
  265.         pfatal_with_name (outname);
  266.       }
  267.     if (nread < sizeof buf)
  268.       break;
  269.       }
  270.   }
  271.  
  272. #ifdef BSD
  273.   if (fsync (outdesc) < 0)
  274.     pfatal_and_delete (outname);
  275. #endif
  276.  
  277.   /* Check to make sure no errors before we zap the inbox.  */
  278.   if (close (outdesc) != 0)
  279.     pfatal_and_delete (outname);
  280.  
  281. #ifdef MAIL_USE_FLOCK
  282. #if defined (STRIDE) || defined (XENIX)
  283.   /* Stride, xenix have file locking, but no ftruncate.  This mess will do. */
  284.   close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
  285. #else
  286.   ftruncate (indesc, 0L);
  287. #endif /* STRIDE or XENIX */
  288. #endif /* MAIL_USE_FLOCK */
  289.  
  290. #ifdef MAIL_USE_MMDF
  291.   lk_close (indesc, 0, 0, 0);
  292. #else
  293.   close (indesc);
  294. #endif
  295.  
  296. #ifndef MAIL_USE_FLOCK
  297.   /* Delete the input file; if we can't, at least get rid of its contents.  */
  298. #ifdef MAIL_UNLINK_SPOOL
  299.   /* This is generally bad to do, because it destroys the permissions
  300.      that were set on the file.  Better to just empty the file.  */
  301.   if (unlink (inname) < 0 && errno != ENOENT)
  302. #endif /* MAIL_UNLINK_SPOOL */
  303.     creat (inname, 0600);
  304. #ifndef MAIL_USE_MMDF
  305.   unlink (lockname);
  306. #endif /* not MAIL_USE_MMDF */
  307. #endif /* not MAIL_USE_FLOCK */
  308.   exit (0);
  309. }
  310.  
  311. /* Print error message and exit.  */
  312.  
  313. fatal (s1, s2)
  314.      char *s1, *s2;
  315. {
  316.   if (delete_lockname)
  317.     unlink (delete_lockname);
  318.   error (s1, s2);
  319.   exit (1);
  320. }
  321.  
  322. /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
  323.  
  324. error (s1, s2, s3)
  325.      char *s1, *s2, *s3;
  326. {
  327.   printf ("movemail: ");
  328.   printf (s1, s2, s3);
  329.   printf ("\n");
  330. }
  331.  
  332. pfatal_with_name (name)
  333.      char *name;
  334. {
  335.   extern int errno, sys_nerr;
  336.   extern char *sys_errlist[];
  337.   char *s;
  338.  
  339.   if (errno < sys_nerr)
  340.     s = concat ("", sys_errlist[errno], " for %s");
  341.   else
  342.     s = "cannot open %s";
  343.   fatal (s, name);
  344. }
  345.  
  346. pfatal_and_delete (name)
  347.      char *name;
  348. {
  349.   extern int errno, sys_nerr;
  350.   extern char *sys_errlist[];
  351.   char *s;
  352.  
  353.   if (errno < sys_nerr)
  354.     s = concat ("", sys_errlist[errno], " for %s");
  355.   else
  356.     s = "cannot open %s";
  357.  
  358.   unlink (name);
  359.   fatal (s, name);
  360. }
  361.  
  362. /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
  363.  
  364. char *
  365. concat (s1, s2, s3)
  366.      char *s1, *s2, *s3;
  367. {
  368.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  369.   char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
  370.  
  371.   strcpy (result, s1);
  372.   strcpy (result + len1, s2);
  373.   strcpy (result + len1 + len2, s3);
  374.   *(result + len1 + len2 + len3) = 0;
  375.  
  376.   return result;
  377. }
  378.  
  379. /* Like malloc but get fatal error if memory is exhausted.  */
  380.  
  381. char *
  382. xmalloc (size)
  383.      unsigned size;
  384. {
  385.   char *result = malloc (size);
  386.   if (!result)
  387.     fatal ("virtual memory exhausted", 0);
  388.   return result;
  389. }
  390.  
  391. /* This is the guts of the interface to the Post Office Protocol.  */
  392.  
  393. #ifdef MAIL_USE_POP
  394.  
  395. #include <sys/socket.h>
  396. #include <netinet/in.h>
  397. #include <netdb.h>
  398. #include <stdio.h>
  399. #include <pwd.h>
  400.  
  401. #ifdef USG
  402. #include <fcntl.h>
  403. /* Cancel substitutions made by config.h for Emacs.  */
  404. #undef open
  405. #undef read
  406. #undef write
  407. #undef close
  408. #endif /* USG */
  409.  
  410. #define NOTOK (-1)
  411. #define OK 0
  412. #define DONE 1
  413.  
  414. char *progname;
  415. FILE *sfi;
  416. FILE *sfo;
  417. char Errmsg[80];
  418.  
  419. static int debug = 0;
  420.  
  421. char *get_errmsg ();
  422. char *getenv ();
  423. int mbx_write ();
  424.  
  425. popmail (user, outfile)
  426.      char *user;
  427.      char *outfile;
  428. {
  429.   char *host;
  430.   int nmsgs, nbytes;
  431.   char response[128];
  432.   register int i;
  433.   int mbfi;
  434.   FILE *mbf;
  435.   struct passwd *pw = (struct passwd *) getpwuid (getuid ());
  436.   if (pw == NULL)
  437.     fatal ("cannot determine user name");
  438.  
  439.   host = getenv ("MAILHOST");
  440.   if (host == NULL)
  441.     {
  442.       fatal ("no MAILHOST defined");
  443.     }
  444.  
  445.   if (pop_init (host) == NOTOK)
  446.     {
  447.       fatal (Errmsg);
  448.     }
  449.  
  450.   if (getline (response, sizeof response, sfi) != OK)
  451.     {
  452.       fatal (response);
  453.     }
  454.  
  455.   if (pop_command ("USER %s", user) == NOTOK
  456.       || pop_command ("RPOP %s", pw->pw_name) == NOTOK)
  457.     {
  458.       pop_command ("QUIT");
  459.       fatal (Errmsg);
  460.     }
  461.  
  462.   if (pop_stat (&nmsgs, &nbytes) == NOTOK)
  463.     {
  464.       pop_command ("QUIT");
  465.       fatal (Errmsg);
  466.     }
  467.  
  468.   if (!nmsgs)
  469.     {
  470.       pop_command ("QUIT");
  471.       return 0;
  472.     }
  473.  
  474.   mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
  475.   if (mbfi < 0)
  476.     {
  477.       pop_command ("QUIT");
  478.       pfatal_and_delete (outfile);
  479.     }
  480.   fchown (mbfi, getuid (), -1);
  481.  
  482.   if ((mbf = fdopen (mbfi, "w")) == NULL)
  483.     {
  484.       pop_command ("QUIT");
  485.       pfatal_and_delete (outfile);
  486.     }
  487.  
  488.   for (i = 1; i <= nmsgs; i++)
  489.     {
  490.       mbx_delimit_begin (mbf);
  491.       if (pop_retr (i, mbx_write, mbf) != OK)
  492.     {
  493.       pop_command ("QUIT");
  494.       close (mbfi);
  495.       unlink (outfile);
  496.       fatal (Errmsg);
  497.     }
  498.       mbx_delimit_end (mbf);
  499.       fflush (mbf);
  500.     }
  501.  
  502.   if (fsync (mbfi) < 0)
  503.     {
  504.       pop_command ("QUIT");
  505.       pfatal_and_delete (outfile);
  506.     }
  507.  
  508.   if (close (mbfi) == -1)
  509.     {
  510.       pop_command ("QUIT");
  511.       pfatal_and_delete (outfile);
  512.     }
  513.  
  514.   for (i = 1; i <= nmsgs; i++)
  515.     {
  516.       if (pop_command ("DELE %d", i) == NOTOK)
  517.     {
  518.       /* Better to ignore this failure.  */
  519.     }
  520.     }
  521.  
  522.   pop_command ("QUIT");
  523.   return (0);
  524. }
  525.  
  526. pop_init (host)
  527.      char *host;
  528. {
  529.   register struct hostent *hp;
  530.   register struct servent *sp;
  531.   int lport = IPPORT_RESERVED - 1;
  532.   struct sockaddr_in sin;
  533.   register int s;
  534.  
  535.   hp = gethostbyname (host);
  536.   if (hp == NULL)
  537.     {
  538.       sprintf (Errmsg, "MAILHOST unknown: %s", host);
  539.       return NOTOK;
  540.     }
  541.  
  542.   sp = getservbyname ("pop", "tcp");
  543.   if (sp == 0)
  544.     {
  545.       strcpy (Errmsg, "tcp/pop: unknown service");
  546.       return NOTOK;
  547.     }
  548.  
  549.   sin.sin_family = hp->h_addrtype;
  550.   bcopy (hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
  551.   sin.sin_port = sp->s_port;
  552.   s = rresvport (&lport);
  553.   if (s < 0)
  554.     {
  555.       sprintf (Errmsg, "error creating socket: %s", get_errmsg ());
  556.       return NOTOK;
  557.     }
  558.  
  559.   if (connect (s, (char *)&sin, sizeof sin) < 0)
  560.     {
  561.       sprintf (Errmsg, "error during connect: %s", get_errmsg ());
  562.       close (s);
  563.       return NOTOK;
  564.     }
  565.  
  566.   sfi = fdopen (s, "r");
  567.   sfo = fdopen (s, "w");
  568.   if (sfi == NULL || sfo == NULL)
  569.     {
  570.       sprintf (Errmsg, "error in fdopen: %s", get_errmsg ());
  571.       close (s);
  572.       return NOTOK;
  573.     }
  574.  
  575.   return OK;
  576. }
  577.  
  578. pop_command (fmt, a, b, c, d)
  579.      char *fmt;
  580. {
  581.   char buf[128];
  582.   char errmsg[64];
  583.  
  584.   sprintf (buf, fmt, a, b, c, d);
  585.  
  586.   if (debug) fprintf (stderr, "---> %s\n", buf);
  587.   if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK;
  588.  
  589.   if (getline (buf, sizeof buf, sfi) != OK)
  590.     {
  591.       strcpy (Errmsg, buf);
  592.       return NOTOK;
  593.     }
  594.  
  595.   if (debug)
  596.     fprintf (stderr, "<--- %s\n", buf);
  597.   if (*buf != '+')
  598.     {
  599.       strcpy (Errmsg, buf);
  600.       return NOTOK;
  601.     }
  602.   else
  603.     {
  604.       return OK;
  605.     }
  606. }
  607.  
  608.     
  609. pop_stat (nmsgs, nbytes)
  610.      int *nmsgs, *nbytes;
  611. {
  612.   char buf[128];
  613.  
  614.   if (debug)
  615.     fprintf (stderr, "---> STAT\n");
  616.   if (putline ("STAT", Errmsg, sfo) == NOTOK)
  617.     return NOTOK;
  618.  
  619.   if (getline (buf, sizeof buf, sfi) != OK)
  620.     {
  621.       strcpy (Errmsg, buf);
  622.       return NOTOK;
  623.     }
  624.  
  625.   if (debug) fprintf (stderr, "<--- %s\n", buf);
  626.   if (*buf != '+')
  627.     {
  628.       strcpy (Errmsg, buf);
  629.       return NOTOK;
  630.     }
  631.   else
  632.     {
  633.       sscanf (buf, "+OK %d %d", nmsgs, nbytes);
  634.       return OK;
  635.     }
  636. }
  637.  
  638. pop_retr (msgno, action, arg)
  639.      int (*action)();
  640. {
  641.   char buf[128];
  642.  
  643.   sprintf (buf, "RETR %d", msgno);
  644.   if (debug) fprintf (stderr, "%s\n", buf);
  645.   if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK;
  646.  
  647.   if (getline (buf, sizeof buf, sfi) != OK)
  648.     {
  649.       strcpy (Errmsg, buf);
  650.       return NOTOK;
  651.     }
  652.  
  653.   while (1)
  654.     {
  655.       switch (multiline (buf, sizeof buf, sfi))
  656.     {
  657.     case OK:
  658.       (*action)(buf, arg);
  659.       break;
  660.     case DONE:
  661.       return OK;
  662.     case NOTOK:
  663.       strcpy (Errmsg, buf);
  664.       return NOTOK;
  665.     }
  666.     }
  667. }
  668.  
  669. getline (buf, n, f)
  670.      char *buf;
  671.      register int n;
  672.      FILE *f;
  673. {
  674.   register char *p;
  675.   int c;
  676.  
  677.   p = buf;
  678.   while (--n > 0 && (c = fgetc (f)) != EOF)
  679.     if ((*p++ = c) == '\n') break;
  680.  
  681.   if (ferror (f))
  682.     {
  683.       strcpy (buf, "error on connection");
  684.       return NOTOK;
  685.     }
  686.  
  687.   if (c == EOF && p == buf)
  688.     {
  689.       strcpy (buf, "connection closed by foreign host");
  690.       return DONE;
  691.     }
  692.  
  693.   *p = NULL;
  694.   if (*--p == '\n') *p = NULL;
  695.   if (*--p == '\r') *p = NULL;
  696.   return OK;
  697. }
  698.  
  699. multiline (buf, n, f)
  700.      char *buf;
  701.      register int n;
  702.      FILE *f;
  703. {
  704.   if (getline (buf, n, f) != OK)
  705.     return NOTOK;
  706.   if (*buf == '.')
  707.     {
  708.       if (*(buf+1) == NULL)
  709.     return DONE;
  710.       else
  711.     strcpy (buf, buf+1);
  712.     }
  713.   return OK;
  714. }
  715.  
  716. char *
  717. get_errmsg ()
  718. {
  719.   extern int errno, sys_nerr;
  720.   extern char *sys_errlist[];
  721.   char *s;
  722.  
  723.   if (errno < sys_nerr)
  724.     s = sys_errlist[errno];
  725.   else
  726.     s = "unknown error";
  727.   return (s);
  728. }
  729.  
  730. putline (buf, err, f)
  731.      char *buf;
  732.      char *err;
  733.      FILE *f;
  734. {
  735.   fprintf (f, "%s\r\n", buf);
  736.   fflush (f);
  737.   if (ferror (f))
  738.     {
  739.       strcpy (err, "lost connection");
  740.       return NOTOK;
  741.     }
  742.   return OK;
  743. }
  744.  
  745. mbx_write (line, mbf)
  746.      char *line;
  747.      FILE *mbf;
  748. {
  749.   fputs (line, mbf);
  750.   fputc (0x0a, mbf);
  751. }
  752.  
  753. mbx_delimit_begin (mbf)
  754.      FILE *mbf;
  755. {
  756.   fputs ("\f\n0, unseen,,\n", mbf);
  757. }
  758.  
  759. mbx_delimit_end (mbf)
  760.      FILE *mbf;
  761. {
  762.   putc ('\037', mbf);
  763. }
  764.  
  765. #endif /* MAIL_USE_POP */
  766.